/**

 * DBStore.java
 *
 * Copyright (C) 2009,  Tomislav Milkovic
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
package extjsdyntran.translation.store.services;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Properties;
import java.util.Set;
import java.util.Map.Entry;

import extjsdyntran.translation.ITranslationService;
import extjsdyntran.translation.TranslationServiceAbstract;
import extjsdyntran.translation.store.AStore;
import extjsdyntran.translation.store.db.DBaseFactory;
import extjsdyntran.translation.store.db.IRecord;
import extjsdyntran.translation.store.schema.LanguagesPojo;
import extjsdyntran.translation.store.schema.LanguagesTable;
import extjsdyntran.translation.store.schema.TranslationsPojo;
import extjsdyntran.translation.store.schema.TranslationsTable;

public class DBStore extends AStore {

	private String name ;
	private String host ;
	private LanguagesTable tableLang ;
	private TranslationsTable tableTrans ;

	public  DBStore(HashMap<String,String> params)throws Exception {
		super(params);
		host = params.get("host");
		name = params.get("name");
		boolean ists = false;
		if(host!=null){
			ists = DBaseFactory.getInstance(name,host);
		}else
			ists = DBaseFactory.getInstance(name);
		if(!ists){
			throw new Exception("Store not initialized");
		}
		
		tableLang = new LanguagesTable();
		tableTrans = new TranslationsTable();
	}


	public void loadLanguage(ITranslationService service, String language)throws Exception{
		//get language ID
		LanguagesPojo lp = (LanguagesPojo) tableLang.sqlGetByValue(language);
		if(lp==null) {
			logger.warn("Requested language {} not found in storage",language);
			return;
		}
		logger.info("Loading translations for language {}",language);
		//get all translations by langid
		ArrayList<IRecord> recs = tableTrans.sqlGetAllByLanguage(lp.getId());
		Iterator<IRecord> it = recs.iterator();
		while (it.hasNext()){
			//LOAD translation
			TranslationsPojo trec = (TranslationsPojo) it.next();
			//load default language - ENGLISH
			TranslationsPojo mrec = (TranslationsPojo)tableTrans.sqlGetById(trec.getRefId());
			if(mrec!=null){
				service.appendTranslationToCache(language, mrec.getText(), trec.getText());
			}else{
				logger.info("No parent language for language {} ", language );
				//this should be default language, so don't load
				break;
			}			
		}
	}
	
	//if language does not exists in database, create it
	private LanguagesPojo getLanguage(String language){
		LanguagesPojo lp = (LanguagesPojo) tableLang.sqlGetByValue(language);
		if(lp==null){
			lp = new LanguagesPojo(tableLang);
			lp.setLanguage(language);
			lp.sqlInsert();
		}
		return lp;
	}
	
	
	private boolean insertRecord(TranslationsPojo tp, int id, int ref, String value){
		tp.setLangId(id);
		//set reference to english translation 
		tp.setRefId(ref);
		tp.setText(value);
		return tp.sqlInsert();
	}
	
	
	//do not use extensive logging here as AJAX translation response will be higher
	//only log when new language is added, db store service will log other messages 
	private boolean saveTranslation(LanguagesPojo fromLanguage, LanguagesPojo toLanguage, String fromValue, String toValue) {

		if (toValue==null) {
			logger.warn("Translation not saved as value is null!");
			return false;
		}
		
		TranslationsPojo tp; 
		int tranId ;

		//get English translation id from value
		tp = (TranslationsPojo)tableTrans.sqlGetByValue(fromValue,fromLanguage.getId() );
		if(tp==null){
			tp = new TranslationsPojo(tableTrans);
			tp.setLangId(fromLanguage.getId());
			tp.setText(fromValue);
			if (tp.sqlInsert()){
				logger.info("New translation saved to storage for value : {} ", fromValue);
			}else logger.warn("Error saving new translation to storage for value : {} ", fromValue);
			
			insertRecord(new TranslationsPojo(tableTrans),toLanguage.getId(),tp.getId(),toValue);
			return true;
		}
		
		tranId = tp.getId();				
		
		//get this language translation by refId of english translation id  
		//tp = (TranslationsPojo)tableTrans.sqlGetByRefId(tp.getId());
		tp = (TranslationsPojo)tableTrans.sqlGetByValue(toValue,toLanguage.getId() );
		//insert if not exists
		if(tp==null) {
			insertRecord(new TranslationsPojo(tableTrans),toLanguage.getId(),tranId,toValue);
			return true;
		}
				
		//update
		if(tp.getText().equals(toValue)) return true;
		tp.setTable(tableTrans);
		tp.setText(toValue);
		tp.sqlUpdate();
		
		return true;
	}
	
	public boolean deleteTranslation(String fromLanguage,  String fromValue) {
		// TODO return message, add exception, set to void
		logger.info("Deleting translation from storage...");
		LanguagesPojo defLang = getLanguage(TranslationServiceAbstract.defaultLanguage);				
		if(defLang==null) {
			logger.warn("Deleting canceled, default language {} not found in storage!",TranslationServiceAbstract.defaultLanguage);
			return false;
		}
		
		LanguagesPojo curLang = getLanguage(fromLanguage);
		if(curLang==null) {
			logger.warn("Deleting canceled, requested language {} not found in storage!",fromLanguage);
			return false;
		}
		
		TranslationsPojo tp = (TranslationsPojo)tableTrans.sqlGetByValue(fromValue,defLang.getId() );
		if(tp==null) {
			logger.warn("Deleting canceled, default record not found for language {} and value : {}!",fromLanguage, fromValue);
			return false;
		}
		
		tp = (TranslationsPojo)tableTrans.sqlGetByRefId(tp.getId());
		if(tp==null) {
			logger.warn("Deleting canceled, translated record not found for language {} and value : {}!",fromLanguage , fromValue);
			return false;
		}
		tp.setTable(this.tableTrans);
 		return tp.sqlDelete();
	}
	
	public boolean saveTranslation( String toLanguage, String fromValue, String toValue) {
		
		LanguagesPojo defLang = getLanguage(TranslationServiceAbstract.defaultLanguage);				
		if(defLang==null) {
			logger.warn("Saving canceled, default language {} not found in storage!",TranslationServiceAbstract.defaultLanguage);
			return false;
		}
		LanguagesPojo curLang = getLanguage(toLanguage);
		if(curLang==null) {
			logger.warn("Saving canceled, requested language {} not found in storage!",toLanguage);
			return false;
		}
		
		saveTranslation(defLang,curLang,fromValue,toValue);
		return true;
	}
	
	public void saveLanguage(ITranslationService service, Properties p,String language)throws Exception{
		
		//we will initiate english if not initiated 			
		LanguagesPojo defLang = getLanguage(TranslationServiceAbstract.defaultLanguage);				
		if(defLang==null) {
			logger.warn("Saving canceled, default language {} not found in storage!",TranslationServiceAbstract.defaultLanguage);
			return ;
		}
		LanguagesPojo curLang = getLanguage(language);
		if(curLang==null) {
			logger.warn("Saving canceled, requested language {} not found in storage!",language);
			return ;
		}
		
		//skip if no change
		if(curLang.getLanguage().equals(defLang.getLanguage())) return;
		
		Set<Entry<Object, Object>> set = p.entrySet();
		for(Entry<?, ?> entry : set){
			
			saveTranslation(defLang,curLang,(String)entry.getKey(),(String)entry.getValue());
						
		}		
		
	}

	public boolean clearTranslation(ITranslationService service,String fromLanguage){
		LanguagesPojo curLang = getLanguage(fromLanguage);
		if(curLang==null) {
			logger.warn("Saving canceled, requested language {} not found in storage!",fromLanguage);
			return false;
		}
		
		
		ArrayList<IRecord> tpr = tableTrans.sqlGetAllByLanguage(curLang.getId() );	
		Iterator it = tpr.iterator();
		while(it.hasNext()){
			TranslationsPojo tp = (TranslationsPojo) it.next();
			tp.setTable(this.tableTrans);
			tp.sqlDelete();
		}
		
		if (service.isNewLanguageSupported()){
			curLang.setTable(this.tableLang);
			curLang.sqlDelete();
		}
		return true;
	}
	
}
